import struct
from collections import OrderedDict

from tdxpy.parser.base import BaseParser
from tdxpy.helper import get_datetime
from tdxpy.helper import get_price
from tdxpy.helper import get_volume


class GetIndexBarsCmd(BaseParser):

    def setup(self):
        pass

    def __init__(self, client, lock=None):
        super().__init__(client, lock)
        self.category = None

    def setParams(self, category, market, code, start, count):
        code = code.encode('utf-8') if type(code) is str else code

        self.category = category

        values = (
            0x10c,
            0x01016408,
            0x1c,
            0x1c,
            0x052d,
            market,
            code,
            category,
            1,
            start,
            count,
            0, 0, 0  # I + I +  H total 10 zero
        )

        pkg = struct.pack('<HIHHHH6sHHHHIIH', *values)
        self.send_pkg = pkg

    def parseResponse(self, body_buf):
        pos = 2

        (ret_count,) = struct.unpack('<H', body_buf[0: pos])
        # pos += 2

        klines = []

        pre_diff_base = 0

        for i in range(ret_count):
            year, month, day, hour, minute, pos = get_datetime(self.category, body_buf, pos)

            price_open_diff, pos = get_price(body_buf, pos)
            price_close_diff, pos = get_price(body_buf, pos)

            price_high_diff, pos = get_price(body_buf, pos)
            price_low_diff, pos = get_price(body_buf, pos)

            (vol_raw,) = struct.unpack('<I', body_buf[pos: pos + 4])
            pos += 4

            vol = get_volume(vol_raw)


            (dbvol_raw,) = struct.unpack('<I', body_buf[pos: pos + 4])
            pos += 4

            dbvol = get_volume(dbvol_raw)


            (up_count, down_count) = struct.unpack('<HH', body_buf[pos: pos + 4])
            pos += 4

            open = self._cal_price1000(price_open_diff, pre_diff_base)

            price_open_diff = price_open_diff + pre_diff_base

            close = self._cal_price1000(price_open_diff, price_close_diff)
            high = self._cal_price1000(price_open_diff, price_high_diff)
            low = self._cal_price1000(price_open_diff, price_low_diff)

            pre_diff_base = price_open_diff + price_close_diff

            #### 为了避免python处理浮点数的时候，浮点数运算不精确问题，这里引入了多余的代码

            kline = OrderedDict([
                ('open', open),
                ('close', close),
                ('high', high),
                ('low', low),
                ('vol', vol),
                ('amount', dbvol),
                ('year', year),
                ('month', month),
                ('day', day),
                ('hour', hour),
                ('minute', minute),
                ('datetime', '%d-%02d-%02d %02d:%02d' % (year, month, day, hour, minute)),
                ('up_count', up_count),
                ('down_count', down_count)
            ])

            klines.append(kline)

        return klines

    @staticmethod
    def _cal_price1000(base_p, diff):
        return float(base_p + diff) / 1000
